---
title: 阻塞和非阻塞、同步和异步
---
阻塞和非阻塞 、 同步和异步是 IO 编程中两组不同维度的概念，阻塞和非阻塞是指线程访问资源的方式，同步和异步是指线程获取结果的方式。

## 阻塞和非阻塞
线程访问资源，该资源是否准备就绪的一种处理方式
1. 阻塞是指线程会等待资源准备就绪，再继续执行
2. 非阻塞是指线程不会等待资源准备就绪，而是直接返回，可通过轮询的方式来判断资源是否准备就绪

:::tip
阻塞是指线程等待操作完成后才返回，非阻塞是指程序不等待操作完成而立即返回，可通过轮询等方式查看操作状态。
:::

## 同步和异步
同步和异步是指线程获取结果的方式
1. 同步是指调用后，必须等到调用返回后才能继续执行后续操作
2. 异步是指调用后，不必等到调用返回，可继续执行后续操作

## 示例
假设有一个任务是读取文件并处理数据，我们可以用不同的方式来描述这个任务的性质。
### 阻塞同步
在阻塞同步模式下，程序会发起文件读取操作，但它会一直等待文件读取完成后才返回，期间不会做任何其他事情。
```java
// 阻塞同步读取文件
String data = readFileBlocking("example.txt");  // 阻塞等待文件读取完成
processData(data);  // 处理数据
```
### 非阻塞同步
在非阻塞同步模式下，程序会发起文件读取操作，但它不会等待文件读取完成，而是立即返回，然后通过轮询的方式来判断文件是否读取完成。
```java
// 非阻塞同步读取文件
String data = null;
while (data == null) {
    data = readFileNonBlocking("example.txt");  // 非阻塞读取文件
}
processData(data);  // 处理数据
```
### 非阻塞异步
在非阻塞异步模式下，程序会发起文件读取操作，它不会等待文件读取完成，而是立即返回，然后通过回调的方式来处理文件读取完成后的结果。
```java
// 非阻塞异步读取文件
readFileNonBlocking("example.txt", data -> {  // 异步读取文件
    processData(data);  // 处理数据
});

// 处理函数
void processData(String data) {
    // 处理数据
}

```


## BIO
同步阻塞IO，Block IO

* 阻塞式 I/O 模型，每个 I/O 操作会阻塞线程，指导操作完成
* 一对一，每个连接需要一个线程处理
* 适用于连接数少，连接时间较长的场景

![image-20230924010217172](https://img.wkq.pub/img/image-20230924010217172.png)

![image-20230924011213240](https://img.wkq.pub/img/image-20230924011213240.png)

1. 效率较低，系统资源消耗大

## NIO 

同步非阻塞IO，Non Block IO

1. 非阻塞I/O,每个 I/O 操作都是非阻塞的，线程不会等待 I/O 完成。
2. 一对多模型，一个线程可以处理多个连接。
3. 通过 Selector 实现多路复用，监听多个通道的 I/O 事件

![image-20230924010554952](https://img.wkq.pub/img/image-20230924010554952.png)

![image-20230924011233060](https://img.wkq.pub/img/image-20230924011233060.png)

1. 效率较高，一个线程可以处理多个连接。
2. 适用于连接数较多，连接时间短的场景，比如聊天服务器、游戏服务器等

## AIO

异步非阻塞IO

在 NIO 原有的基础上，引入了异步的概念，在读写的时候，返回 Feature 对象 。

* 异步I/O模型，I/O 操作可以异步进行，不会阻塞线程。
* 一对多模型，一个线程可以处理多个连接。

![image-20230924011246716](https://img.wkq.pub/img/image-20230924011246716.png)

1. 相对比 NIO、BIO 在处理同样数量连接时，可能会消耗更多的系统资源。

## BIO、NIO、AIO 的区别

- BIO适用于连接数少、连接时间较长的场景，简单易用。
- NIO适用于连接数较多、连接时间短的场景，效率较高。
- AIO适用于高并发、连接时间较短的场景，效率高但实现可能不稳定。
